#include "ray3df.h"
#include "plane.h"
#include "aabbox3df.h"

bool mt::ray3df::operator==(const ray3df & r) const
{
	using namespace DirectX;
	XMVECTOR r1p = XMLoadFloat3(&Position.Data);
	XMVECTOR r2p = XMLoadFloat3(&r.Position.Data);
	XMVECTOR r1d = XMLoadFloat3(&Direction.Data);
	XMVECTOR r2d = XMLoadFloat3(&r.Direction.Data);
	return XMVector3Equal(r1p, r2p) && XMVector3Equal(r1d, r2d);
}

bool mt::ray3df::operator!=(const ray3df & r) const
{
	using namespace DirectX;
	XMVECTOR r1p = XMLoadFloat3(&Position.Data);
	XMVECTOR r2p = XMLoadFloat3(&r.Position.Data);
	XMVECTOR r1d = XMLoadFloat3(&Direction.Data);
	XMVECTOR r2d = XMLoadFloat3(&r.Direction.Data);
	return XMVector3NotEqual(r1p, r2p) && XMVector3NotEqual(r1d, r2d);
}

//bool mt::ray3df::Intersects(const DirectX::BoundingSphere & sphere, float & Dist) const
//{
//	return sphere.Intersects(Position.Data, Direction.Data, Dist);
//}
//
//bool mt::ray3df::intersects(const DirectX::BoundingBox & box, float & Dist) const
//{
//	return box.Intersects(Position.Data, Direction.Data, Dist);
//}

bool mt::ray3df::intersects(const vec3f & tri0, const vec3f & tri1, const vec3f & tri2, float & Dist) const
{
	using namespace DirectX;
	XMVECTOR ori = XMLoadFloat3(&Position.Data);
	XMVECTOR dir = XMLoadFloat3(&Direction.Data);
	XMVECTOR v0 = XMLoadFloat3(&tri0.Data);
	XMVECTOR v1 = XMLoadFloat3(&tri1.Data);
	XMVECTOR v2 = XMLoadFloat3(&tri2.Data);
	return TriangleTests::Intersects(ori, dir, v0, v1, v2, Dist);
}

bool mt::ray3df::intersects(const plane & plane, float & Dist) const
{
	using namespace DirectX;

	XMVECTOR p = XMLoadFloat4(&plane.Data);
	XMVECTOR dir = XMLoadFloat3(&Direction.Data);

	XMVECTOR nd = XMPlaneDotNormal(p, dir);

	if (XMVector3LessOrEqual(XMVectorAbs(nd), g_RayEpsilon))
	{
		Dist = 0.f;
		return false;
	}
	else
	{
		// t = -(dot(n,origin) + D) / dot(n,dir)
		XMVECTOR pos = XMLoadFloat3(&Position.Data);
		XMVECTOR v = XMPlaneDotNormal(p, pos);
		v = XMVectorAdd(v, XMVectorSplatW(p));
		v = XMVectorDivide(v, nd);
		float dist = -XMVectorGetX(v);
		if (dist < 0)
		{
			Dist = 0.f;
			return false;
		}
		else
		{
			Dist = dist;
			return true;
		}
	}
}

bool mt::ray3df::intersects(const aabbox3df & box,float& Dist) const
{
	return box.intersectsWithRay(*this, Dist);
}
